/**
 * 常用模型
 * 1. 传送带
 */

import * as THREE from "./three.js/build/three.module.js";

import { ExCylinderGeometry } from "./A3Geometrys.js";
import A3Actor from "./A3Actor.js";
import { 
  AxisZ, 
  getMeshShape, 
  isNull, HPI, AxisX, AxisY, CollisionFlags, createCompoundShape } from "./A3Common.js";
import { A3HingeConstraint } from "./A3Constraint.js";
import A3BasicShape from "./A3BasicShape.js";

import { contactsMap } from "./A3Class.js";

class A3Conveyer extends A3Actor {
  name='conveyer';

  loaders = new Map();
  maxLoaderHeight = 100;

  // 传送带参数
  speed = 1.5;
  maxForce = .1;

  padColor = 0x0c0c0c;
  color = 0xeeeeee;

  constructor( radius, width, depth ) {
    super();

    radius = isNull( radius ) ? 0.5 : radius;
    width = isNull( width ) ? 1 : width;
    depth = isNull( depth ) ? 3 : depth;

    const geometry = new ExCylinderGeometry( radius, width, depth, 8, 1, 1 );
    // const geometry = new THREE.BoxGeometry( width, width, depth, 8, 1, 1 );
    geometry.rotateX( Math.PI / 2 );
    geometry.rotateY( Math.PI / 2 );
    const baseMesh = new THREE.Mesh( geometry, new THREE.MeshPhongMaterial({ color: this.color }) );
    const padMesh = new THREE.Mesh( new THREE.BoxGeometry( width, 0.01, depth ), new THREE.MeshPhongMaterial({ color: this.padColor }));
    padMesh.position.set( 0, radius, 0 );
    this.threeObject = new THREE.Group();
    this.threeObject.add( baseMesh );
    this.threeObject.add(padMesh );

    this.physicsShape = getMeshShape( baseMesh, null, false );

    // this.init(10);
    // this.setFromMesh ( baseMesh, 100, this.position );

    this.width = width;
    this.height = radius * 2;
    this.length = depth;

    this.boundLength = depth / 2 + radius;
    this.boundWidth = width / 2;

    this.position.set( 0, radius, 0 );
    this.init(0);

    // this.enableMatertial();
    // this.enableShadow();
    // this.setFriction(0);

  }

  isOnConveyer( loader ) {
    // todo: 优化判定条件
    return (Math.abs( loader.position.z - this.position.z ) <= this.boundLength)
    && Math.abs( loader.position.x - this.position.x ) <= this.boundWidth;

  }

  setSpeed( speed ) {
    this.speed = speed;
  }

  updateLoaders() {

    const loaders = contactsMap.get( this );

    if( !isNull(loaders) ){
      const tmp = new THREE.Vector3( 0, 0, this.speed);
      tmp.applyQuaternion( this.quaternion ) ;
          
      for( var i = 0, il = loaders.length; i < il; i++ ) {
        if( this.isOnConveyer( loaders[i].actor ) ){
          loaders[i].actor.setLinearVelocity( tmp );
        }
      }
    }
  }

  update() {
    // super.update();

    if( this.needsUpdate ) {

      this.updateWorldTransform( this.position, this.quaternion );
      this.needsUpdate = false;

      const tmp = new THREE.Vector3( this.width / 2, 0, this.length / 2 );
      tmp.applyQuaternion( this.quaternion );

      this.boundWidth = Math.abs(tmp.x);
      this.boundLength = Math.abs(tmp.z);

      console.log( tmp )
    }
  
    this.updateLoaders();
    // console.log( this.loaders)

  }

}

// 滚筒型传送带
class A3RolerConveyer extends A3Actor {
  name='conveyer';

  // 滚筒
  rolerRadius = .5;
  rolerCount = 16;
  rolerWidth = 1;
  rolerColor = 0x0c0c0c;
  rolers = [];

  color = 0xeeeeee;
  
  maxForce = 1;

  // 速度
  speed = 5;

  constructor( radius, width, depth ) {
    super();

    const geometry = new ExCylinderGeometry( radius, width, depth, 8, 1, 1 );
    this.material = new THREE.MeshPhongMaterial( { color: this.color } );
    geometry.rotateX( Math.PI / 2 );
    geometry.rotateY( Math.PI / 2 );
    const mesh = new THREE.Mesh( geometry,  this.material );
    this.threeObject = mesh;

    const conveyerShape = getMeshShape( mesh, null, false );
    
    this.physicsShape = createCompoundShape();
    this.physicsShape.addChild(conveyerShape)

    this.width = width;
    this.length = depth + radius * 2;
    this.height = radius * 2;

    this.position.set( 0, radius, 0 );

    this.rolerRadius = radius * 1.2;
    this.rolerWidth = this.width;

    this.createRolers( this.rolerCount );
    
    this.init();

  }

  init(){

    const quat = new THREE.Quaternion().setFromAxisAngle( AxisZ, HPI );
    for(var i = 0, il = this.rolers.length; i < il; i++ ) {
      this.rolers[i].init();
      this.rolers[i].physicsBody.setCollisionFlags(CollisionFlags.CF_NO_CONTACT_RESPONSE);
      const pos = new THREE.Vector3( 0, 0, (0.5 - i / (il-1)) * this.length);
      // 添加约束
      const constraint = new A3HingeConstraint( this, this.rolers[i] );
      constraint.setBodyA(
        pos,
        AxisX
      )
      constraint.setBodyB(
        new THREE.Vector3( 0, 0, 0 ),
        AxisY
      )
      this.rolers[i].constraint = constraint;

      this.physicsShape.addChild( this.rolers[i].physicsShape, pos, quat );
    }

    super.init();

  }

  createRolers( count ) {
    count = isNaN( count ) || count < 1 ? 1 : Math.floor( count );
    const rolerRadius = this.rolerRadius;
    const rolerWidth = this.rolerWidth;
    const rolerMaterial = new THREE.MeshPhongMaterial({ color: this.rolerColor });
    const tmpPos = this.position.clone();
    const tmpQuat = new THREE.Quaternion().setFromAxisAngle( AxisZ, -HPI );
    const zStep = this.length / count;

    for( var i = 0; i < count; i++ ) {

      const roler = new A3BasicShape('Cylinder', rolerRadius, rolerRadius, rolerWidth );
      roler.setMaterial( rolerMaterial );
      tmpPos.z = (0.5 - i / ( count - 1 )) * this.length;
      roler.setPosition( tmpPos );
      roler.setQuaternion( tmpQuat )
      roler.setMass(1.0);
      roler.setFriction(100)
      this.rolers.push( roler );

    }
  }

  setPosition( position ) {
    super.setPosition( position );

    const tmpPos = position.clone();
    const step = this.length / this.rolers.length;
    for( var i = 0, il = this.rolers.length; i < il; i++ ) {
      const roler = this.rolers[i];
      const p = i / (il - 1);
      tmpPos.z = (0.5 - p) * this.length;
      roler.setPosition( tmpPos );
    }

  }

  addToWord( parent ) {
    super.addToWord( parent );

    for( var i = 0, il = this.rolers.length; i < il; i++ ) {
      parent.addActor( this.rolers[i] );
      // console.log( this.rolers[i] );
      if( this.rolers[i].constraint ) {
        parent.addActor( this.rolers[i].constraint );
        this.rolers[i].constraint.enableConstraint(true, this.speed);
      }
    }

  }

  updateLoaders(){
    const tmp = new THREE.Vector3( 0, 0, this.speed );
    tmp.applyQuaternion( this.quaternion );

    for( var i = 1, il = this.rolers.length; i < il; i++ ) {
      const roler = this.rolers[i];

      if( contactsMap.has(roler) ) {
        const loaders =  contactsMap.get(roler);
        for( var j = 0, jl = loaders.length; j < jl; j++ ) {
          loaders[j].actor.setLinearVelocity( tmp );
          // loaders[j].actor.applyForce( new THREE.Vector3( 0, 0, 1 ) );
          
        }
      }
    }
  }

  update(){

    if( this.needsUpdate ) {

      this.updateWorldTransform( this.position, this.quaternion );
      this.needsUpdate = false;
    }

    this.updateLoaders();
  }
}

export {
  A3Conveyer,
  A3RolerConveyer,
}